#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


#define COMMIND_SIZE 1024
#define FORMAT "[%s@%s:%s]# "
#define MAX_SIZE 128

int argc = 0;
char* argv[MAX_SIZE];
char cwd[128];

int lastcode = 0;

char* env[100];
int envs = 0;

const char* GetUserName()
{
    const char* username = getenv("USER");
    return username == NULL ? "None" : username;
}

const char* GetHostName()
{
    setenv("HOSTNAME","VM-8-17-ubuntu",1);
    const char* HostName = getenv("HOSTNAME");
    return HostName == NULL ? "None" : HostName;
}

const char* GetPWD()
{
    //const char* PWD = getenv("PWD");
    char* rcwd = getcwd(cwd,sizeof(cwd));
    return rcwd == NULL ? "None" : rcwd;
}


std::string DirName(const char* pwd)
{
#define SLASH "/"
    std::string dir = pwd;
    if(dir == SLASH)
    return SLASH;
    auto pos = dir.rfind(SLASH);
    if(pos == std::string::npos)return "BUG";
    return dir.substr(pos+1);

}


void Makecommline(char str[],int size)
{
    //snprintf格式：  参数1：用于存储数据 
    //                参数2: 读取的字节
    //                参数3: 打印格式
   // snprintf(str,size,FORMAT,GetUserName(),GetHostName(),GetPWD());
   snprintf(str,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPWD()).c_str());
   
}

// 输出命令提示符
void printcommline()
{
    char commline[COMMIND_SIZE] = {0};
    Makecommline(commline,sizeof(commline));
    printf("%s",commline);
    fflush(stdout);  //刷新屏幕

}

bool Getcomline(char* commline,int size)
{
    //fgets         参数1：将读取到的数据存储到该数组中
    //              参数2：读取的字数
    char* res = fgets(commline,size,stdin);
    if(res == NULL)
        return false;
    commline[strlen(commline)-1] = 0;
    if(strlen(commline)==0)
        return false;
    //printf("%s",commline);
    return true;


}

//命令行分析 "ls -a -l"  -> "ls" "a" "l"
void CommandParse(char* commandline)
{
    #define SEP " "
    argc = 0;
    argv[argc++] = strtok(commandline,SEP);
    while((bool)(argv[argc++] = strtok(nullptr,SEP)));
    argc--;
}

void printarg()
{
    int i = 0;
    for(;argv[i];i++)
    {
        printf("argv[%d]%s\n",i,argv[i]);
    }
    //printf("\n");
    printf("%d\n",argc);
}

void execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        execvp(argv[0],argv);
        exit(1);
    }
    if(id > 0)
    {
        int status = 0;
        pid_t rid = waitpid(id,&status,0);//阻塞等待
        lastcode = WEXITSTATUS(status); //将子进程退出码存放到lastcode
    }

}

const char* GetHome()
{
    const char* name = getenv("HOME");
    return name == NULL ? "None" : name;
}

bool Cd()
{

    if(argc == 1)
    {
        std::string home = GetHome();
       // if(home.empty()) return true;
        chdir(home.c_str()); //转换成C语言字符
    }
    else
    {
        std::string where = argv[1];
        if(where == "~")
        {
        }
        else if(where == "-")
        {
        }
        else
            chdir(where.c_str());
    }
    return true;
}

void Echo()
{
    if(argc == 2)
    {
        std::string opt = argv[1];
        if(opt == "$?")
        {
            std::cout << lastcode << std::endl;
            lastcode = 0;
        }
        else if(opt[0] == '$')
        {
            std::string env_name = opt.substr(1);//拿到$往后的字符串
            
            const char* env_value = getenv(env_name.c_str());
            if(env_value)
            {
                std::cout << env_value << std::endl;
            }
        }
    }
}


//内键命令
bool CheckAndExecBuiltin()
{
    //直接使用C++的stl库更加方便
   // if(strcmp(argv[0],"cd") == 0)
   // {
   //     Cd();
   //     return true;
   // }
    std::string cmd = argv[0];
    if(cmd == "cd")
    {
        Cd();
        return true;
    }
    else if(cmd == "echo")
    {
        Echo();
        return true;
    }

    return false;
}


void Initenv()
{
    extern char** environ;
    memset(env,0,sizeof(env));
    envs = 0;
    //获取环境变量
    for(int i = 0;environ[i];i++)
    {
        env[i] = (char*)malloc(strlen(environ[i])+1);
        strcpy(env[i],environ[i]);
        envs++;
    }
    env[envs++] = (char*)"www=11111";
    env[envs] = NULL;
    //导成环境变量
    for(int i = 0;env[i];i++)
    {
        putenv(env[i]);
    }
    environ = env;
}

int main()
{
    Initenv();
   // std::string home = GetHome();
   // printf("%s\n",home.c_str());
    while(true)
    {
    // 1. 输出命令提示符
    printcommline();

    // 2.获取输入的命令
    char commline[COMMIND_SIZE] = {0};
    Getcomline(commline,sizeof(commline));

    // 3.命令行分析
    CommandParse(commline);
   // printarg();
    
    // 4. 内键命令
    if(CheckAndExecBuiltin())
        continue;

    // 5.执行命令
    execute();
    }
    return 0;
}

